#!/usr/bin/python
#encoding: utf-8
import os
import sys
import socket
import hashlib
import logging
import datetime
import ConfigParser 

def md5sum(filename):
    '''获取md5值'''
    fd = open(filename,"r")
    fcont = fd.read()
    fd.close()
    fmd5 = hashlib.md5(fcont)
    return fmd5.hexdigest()

def get_log(content):
    '''记录日志'''
    dtime = datetime.datetime.now().strftime('%Y-%m-%d')
    with open('./log/%s.log'%dtime,'a+') as f:
        f.write(content,)


class Cf:

    __confile = "svnsync.conf"
    
    conf = ConfigParser.ConfigParser() #读取配置文件
    conf.read('%s'%__confile)
    
    def get_bind_host(self):
        '''从配置中读取本地HOST'''
        HOST = self.conf.get('bind','host')
        return HOST 

    def get_bind_port(self):
        '''从配置中读取本地Bind端口'''
        PORT = int(self.conf.get('bind','port'))
        return PORT

    def get_remote_host(self):
        '''从配置中读取Server端HOST'''
        remote_host = self.conf.get('remote','host')
        return remote_host

    def get_remote_port(self):
        '''从配置中读取Server端的端口'''
        remote_port = int(self.conf.get('remote','port'))
        return remote_port

    def get_base_dir(self):
        '''从配置中读取本地SVN的配置存放目录'''
        base_dir = self.conf.get('info','base_dir')
        return base_dir
        
    def get_bak_dir(self):     
        '''从配置中读取备份存放地址'''
        bak_dir = self.conf.get("info",'bak_dir')
        return bak_dir
       
    def get_authfile(self):
        '''从配置中读取authfile文件地址'''
        authfile = self.conf.get('info','authfile')
        return authfile

    def get_passfile(self):
        '''从配置中读取password文件地址'''
        passfile = self.conf.get('info','passfile')
        return passfile

    def get_key(self):
        '''从配置中读取key'''
        key = self.conf.get('info','key')
        return key

    def get_rsync_model(self):
        '''从配置中读取Server端的rsync模块名称，用于同步文件'''
        rsync_model = self.conf.get('rsync_info','model')
        return rsync_model
    
class SvnSync:    
    '''文件同步类''' 
    cf = Cf()

    HOST = cf.get_bind_host() 
    PORT = cf.get_bind_port() 
    remote_host = cf.get_remote_host() 
    remote_port = cf.get_remote_port()

    base_dir = cf.get_base_dir() 
    bak_dir = cf.get_bak_dir() 
    authfile = cf.get_authfile() 
    passfile = cf.get_passfile() 
    key = cf.get_key()
    rsync_model = cf.get_rsync_model() 

    def check_port(self,sname):
        '''检查Server端口是否通'''
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            s.connect(sname)
        except socket.error as e:
            logging.warning('[%s] service connection failed: %s \r\n' % (sname, e))
            return -1
        return 1
        s.close()

    
    def update_svn(self,update_list):
        '''更新SVN配置'''
        now = datetime.datetime.now().strftime('%Y-%m-%d_%H:%M:%S') #获取当前时间，用于记录日志和备份文件
        bakauth = self.bak_dir + self.authfile + '_' +  now #authfile备份文件名
        realauth = self.base_dir + self.authfile #线上实际authfile文件
    
        bakpass = self.bak_dir + self.passfile + '_' + now #password文件备份 
        realpass = self.base_dir + self.passfile #线上实际password文件
    
        if "authz" in update_list:
            os.rename(realauth,bakauth) #备份authz文件
            os.system("rsync -a %s%s%s %s"%(self.remote_host,self.rsync_model,self.authfile,self.base_dir)) #将最新的authz文件从Server端拉回来
            logcont = "authz changed at %s"%now + '\n' 
            get_log(logcont) #记录日志

        if "passwd" in update_list:
            os.rename(realpass,bakpass) #备份passwd文件
            os.system("rsync -a %s%s%s %s"%(self.remote_host,self.rsync_model,self.passfile,self.base_dir)) #将最新的passwd文件从Server端拉回来
            logcont = "passwd changed at %s"%now + '\n' 
            get_log(logcont)
        
    def connect_server(self):
        '''连接Server端'''
        remote_host_info = (self.remote_host,self.remote_port)
        result = self.check_port((remote_host_info))
        if result == -1:
            sys.exit()

        while True:
            ss = socket.socket()
            ss.connect((self.remote_host,self.remote_port))
    
            auth_file = self.base_dir + self.authfile
            auth_md5 = md5sum(auth_file) #获取当前authz文件的md5值
            pass_file = self.base_dir + self.passfile
            pass_md5 = md5sum(pass_file) #获取当前passwd文件的md5值

            send_data = self.key + '-' + str(auth_md5) + '-' + str(pass_md5) #定义传输的数据格式，key+authz的md5值+passwd文件的md5值
    
            try:
                ss.sendall(send_data) #发送数据
            except socket.error:
                print "Send failed"
                sys.exit()
    
            reply = ss.recv(4096) #接收Server端返回的数据，根据返回值进行更新或不更新
            
            update_list = []
    
            if reply.split('-')[1] == '1': #如果authz的字段是1的话，就需要更新authz，如果passwd字段是1的话，就需要更新passwd文件。格式自己定义的,Server端返回数据
                update_list.append('authz')

            if reply.split('-')[2] == '1':
                update_list.append('passwd')

            self.update_svn(update_list) #根据需要进行更新文件
    
            ss.close()
    
            os.system("sleep 5") #5秒钟检查一次
            

